package fnic.prehand.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;

import fnic.jsontrans.TimeOut;

public class ProbeAuthService{
	private static final AgentConfig config = AgentConfig.getInstance();
	private static final HttpMsgService httpInstance = HttpMsgService.getInstance();
	private static final JacksonFormatService jsonInstance = JacksonFormatService.getInstance();
	private static final Logger LOG = Logger.getLogger(ProbeAuthService.class);
	
	private static final int mapSize = config.getSessionKeyMapSize();	
	private static final int sleepinterval = config.getSessionKeySleepInterval();

	private Map<Integer, InnerKeyTime> hashmap = new HashMap<Integer, InnerKeyTime>(mapSize);

	// singleton
//	private static ProbeAuthService instance = new ProbeAuthService();
	
	private final String ctrlSKURL;
//	private String webIp = config.getSkValidIp();
//	private Short webPort = config.getSkValidPort();
	
//	public static ProbeAuthService getInstance() {
//		return instance;
//	}

	public ProbeAuthService(String url){
		ctrlSKURL = url;
	}
	/*
	 * 判断MAP已满
	 */
	public synchronized boolean isMapFull() {
		return (hashmap.size() == mapSize);
	}

	/*
	 * 添加Item
	 */
	public synchronized boolean putItem(int probeid, InnerKeyTime item) {
		if (!isMapFull()) {
			hashmap.put(probeid, item);
			return true;
		} else {
			LOG.error("Probe Auth HashMap full");
			return false;
		}
	}

	/*
	 * 通过probeid删除Item
	 */
	public synchronized boolean delItemByid(int probeid) {
		if (hashmap.containsKey(probeid)) {
			hashmap.remove(probeid);
			return true;
		} else {
			return false;
		}
	}

	/*
	 * 通过probeid删除Item
	 */
	public synchronized void delBulkItem(ArrayList<Integer> ids) {
		Iterator<Integer> itlist = ids.iterator();
		while (itlist.hasNext()) {
			int probeid = itlist.next();
			if (hashmap.containsKey(probeid)) {
				LOG.info("delete one item, probeid:"+probeid+
						 ", sessionKey:"+hashmap.get(probeid).getKeySession()+
						 ", lefttime:"+hashmap.get(probeid).getLeftime());
				hashmap.remove(probeid);
			}
		}
	}

	/*
	 * 判断probeid+keySession是否ES本机校验成功
	 */
	public boolean localAuth(int probe, String session){
		if(session!=null&&hashmap.containsKey(probe)){
			InnerKeyTime obj = hashmap.get(probe);
			if(obj.isLegalProbe(session)){
				return true;
			}
		}
		
		return false;
	}
	
	/*
	 * 循环处理流程，
	 * 找到超时的Item保存到List，
	 * 待删除
	 */
	public synchronized ArrayList<Integer> getTimeOutIdList() {
		ArrayList<Integer> delIdList = null;
		if (!hashmap.isEmpty()) {
			delIdList = new ArrayList<Integer>();
			Iterator<InnerKeyTime> itor = hashmap.values().iterator();
			while (itor.hasNext()) {
				InnerKeyTime obj = itor.next();
				if (obj.cycleTimeOver()) {
					delIdList.add(obj.getProbeid());
				}
			}
		}

		return delIdList;
	}

	public static int getSleepTime(){
		return sleepinterval;
	}

	public boolean validSessionKey(int probeid, String ksession){
		boolean authen = localAuth(probeid, ksession);
		LOG.info("local auth result:"+authen);
		
		if(!authen){
			int lefttime = getSKTimeOut(probeid, ksession);
			LOG.info("ctrl auth over, leftime:"+lefttime);
			if(lefttime>0){
				if(!isMapFull()){
					putItem(probeid, new InnerKeyTime(probeid, lefttime, ksession));
//					LOG.info("put [probeid:"+probeid+"],[sessionKey:"+ksession+"] succeed!");
				}else{
					LOG.error("attention !!! auth queue if full!");
					//本地sessionKey缓存失败--缓存区已满
				}
			}else{
				LOG.error("ctrl auth fail, leftime:"+lefttime);
				//向管理节点请求sessionKey校验失败 -- sk校验失败
				if(config.getSessionKeyFlg() == 1){
					return false;
				}else{
					//向管理节点请求sessionKey校验失败 -- sk校验失败但调试开关打开允许本次通过
				}
			}
		}
		return true;
	}
	
	private int getSKTimeOut(int probeid, String ks){
		int sessionTimeout = -1;
		String url = ctrlSKURL+ "probeId=" + probeid + "&sessionKey="+ ks;
		StringBuilder rspbuilder = new StringBuilder();
		
		//向管理节点发送http消息获得sk timeout
		boolean succeedFg = httpInstance.sendGetMsg(true, url, rspbuilder);
		if(succeedFg){
			if(rspbuilder.length()>0){
				String httprsp = rspbuilder.toString(); //验证一下是否为json格式
				TimeOut out = (TimeOut)jsonInstance.String2Obj(httprsp, "fnic.jsontrans.TimeOut");
				
				if(out!=null){
					sessionTimeout = Integer.parseInt(out.getTimeout());
					//向管理节点请求sessionKey校验失败 -- 解析响应json格式失败
				}
			}
			else{
				LOG.error("[getSKTimeOut]Get Http Rsp length is zero !!");
			}
		}else{
			LOG.error("[getSKTimeOut]Get Http Rsp Code error!!");
		}
		
		return  sessionTimeout;
	}
	
	public static class InnerKeyTime {
		
		public InnerKeyTime(int id, String ks){
			probeid = id;
			keySession = ks;
		}
		
		public InnerKeyTime(int id, int tlft, String ks){
			probeid = id;
			leftime = tlft;
			keySession = ks;
		}
		public String getKeySession() {
			return keySession;
		}

		public void setKeySession(String keySession) {
			this.keySession = keySession;
		}

		public int getLeftime() {
			return leftime;
		}

		public void setLeftime(int leftime) {
			this.leftime = leftime;
		}

		public int getProbeid() {
			return probeid;
		}

		public void setProbeid(int probeid) {
			this.probeid = probeid;
		}

		/*
		 * 循环处理函数
		 * 剩余秒数-sleepinterval
		 */
		public boolean cycleTimeOver(){
			this.leftime -= sleepinterval;
			if(leftime>0){
				return false;
			}else{
				return true;
			}
		}
		
		/*
		 * 单次处理函数
		 * 判断probeid对应的keySession存在且lefttime未超时
		 */
		public boolean isLegalProbe(String session){
			if(leftime>0 && keySession.equals(session)){
				return true;
			}else{
				return false;
			}
		}
		
		private String keySession;
		private int leftime;
		private int probeid;
	}

}
